Pytestでカスタムマークを使って特定のテストのみを実行する
はじめに
データアナリティクス事業本部のkobayashiです。
Pytestでテストケースが増えてきた場合にすべてのテストケースをテスをするのではなく、新しく実装した機能だけとか特定のリソースを使ったテストケースのみをテストしたいといった場面があるかと思います。そのような場合はカスタムマーカーを使うことで解決できるのでその内容をまとめます。
Pytestのカスタムマーカー
pytestではカスタムマーカーを使うことでテストケースにカスタムメタデータを付与することでテストケースをpytest.mark
でマークできます。マークしたテストはpytestの-m
オプションを使うことで実行するテストを指定してしてテストすることができます。
Pytestのカスタムマーカーを使ってみる
環境
- Python: 3.11.4
- pytest: 7.4.3
カスタムマークはモジュール・クラス・関数に付けることができます。さらにparametrizeを使った際にもparametrizeの個々のテストケースにマークを付けることができるので大変便利です。
モジュール、クラス、関数にカスタムマークを付ける
でははじめにモジュール、クラス、関数にカスタムマークを付けてテストを実行してみたいと思います。
import pytest from main import calc_pi # モジュールにカスタムマークを付ける pytestmark = pytest.mark.custom_mark_module # クラスにカスタムマークを付ける @pytest.mark.custom_mark_class class TestPi_1: @pytest.mark.parametrize( ["data_in"], [ pytest.param(1000000), ], ) # 関数にカスタムマークを付ける @pytest.mark.custom_mark_func def test_calc_pi_1(self, data_in): ret = calc_pi(data_in) assert ret > 3.14 @pytest.mark.parametrize( ["data_in"], [ pytest.param(1000000), ], ) def test_calc_pi_2(self, data_in): ret = calc_pi(data_in) assert ret > 3.14 class TestPi_2: @pytest.mark.parametrize( ["data_in"], [ pytest.param(1000000), ], ) def test_calc_pi_3(self, data_in): ret = calc_pi(data_in) assert ret > 3.14 @pytest.mark.parametrize( ["data_in"], [ pytest.param(1000000), ], ) def test_calc_pi_4(self, data_in): ret = calc_pi(data_in) assert ret > 3.14
モジュール全体にカスタムマークを付ける場合はGlobal変数としてカスタムマークを付けます。クラス、関数の場合はデコレータでカスタムマークを指定します。
カスタムマークを付けたテストを実行する
はじめにカスタムマークを指定しない状態でテストを実行してみます。
$ pytest test_main.py ============================= test session starts ============================== collecting ... collected 4 items test_main.py::TestPi_1::test_calc_pi_1[1000000] test_main.py::TestPi_1::test_calc_pi_2[1000000] test_main.py::TestPi_2::test_calc_pi_3[1000000] test_main.py::TestPi_2::test_calc_pi_4[1000000] ======================== 4 passed, 3 warnings in 2.22s ========================= PASSED [ 25%]PASSED [ 50%] PASSED [ 75%]PASSED [100%]
すべてのテストケースがテストされています。
次にカスタムマーカーcustom_mark_module
を付けてテストを実行してみます。
$ pytest -m custom_mark_module test_main.py ============================= test session starts ============================== collecting ... collected 4 items test_main.py::TestPi_1::test_calc_pi_1[1000000] test_main.py::TestPi_1::test_calc_pi_2[1000000] test_main.py::TestPi_2::test_calc_pi_3[1000000] test_main.py::TestPi_2::test_calc_pi_4[1000000] ======================== 4 passed, 3 warnings in 2.22s ========================= PASSED [ 25%]PASSED [ 50%] PASSED [ 75%]PASSED [100%]
このケースでは1つのファイルでしかテストを行っていないのでマークを指定してない状態と同じテスト結果となります。
次にカスタムマーカーcustom_mark_class
を付けてテストを実行してみます。
$ pytest -m custom_mark_class test_main.py ============================= test session starts ============================== collecting ... collected 4 items / 2 deselected / 2 selected test_main.py::TestPi_1::test_calc_pi_1[1000000] test_main.py::TestPi_1::test_calc_pi_2[1000000] ================= 2 passed, 2 deselected, 3 warnings in 0.96s ================== PASSED [ 50%]PASSED [100%]
このケースでは先ほどと違いcustom_mark_class
をつけたクラスのみテストが行われています。
次にカスタムマーカーcustom_mark_func
を付けてテストを実行してみます。
$ pytest -m custom_mark_func test_main.py ============================= test session starts ============================== collecting ... collected 4 items / 3 deselected / 1 selected test_main.py::TestPi_1::test_calc_pi_1[1000000] ================= 1 passed, 3 deselected, 3 warnings in 0.47s ================== PASSED [100%]
このケースではcustom_mark_func
をつけた関数のみテストが行われています。
parametrizeにカスタムマークを付ける
さらにparametrizeの個々のテストケースにマークを付けてテストを実行してみたいと思います。
import pytest from main import calc_pi @pytest.mark.parametrize( ["data_in"], [ pytest.param(1000001, marks=pytest.mark.custom_mark_odd), pytest.param(1000002), pytest.param(1000003, marks=pytest.mark.custom_mark_odd), pytest.param(1000004), ], ) def test_calc_pi(data_in): ret = calc_pi(data_in) assert ret > 3.14
parametrizeの個々のテストケースにマークを付ける場合にはpytest.param
のmarks
パラメータでカスタムマークを指定します。
parametrizeにカスタムマークを付けたテストを実行する
はじめにカスタムマークを指定しない状態でテストを実行してみます。
$ pytest test_main2.py ============================= test session starts ============================== collecting ... collected 4 items test_main.py::test_calc_pi[1000001] test_main.py::test_calc_pi[1000002] test_main.py::test_calc_pi[1000003] test_main.py::test_calc_pi[1000004] ======================== 4 passed, 2 warnings in 1.86s ========================= PASSED [ 25%]PASSED [ 50%]PASSED [ 75%]PASSED [100%]
カスタムマーカーcustom_mark_odd
を付けてテストを実行してみます。custom_mark_odd
をつけたparametrize内のテストケースのみテストが行われていることがわかります。
$ pytest -m custom_mark_odd test_main2.py ============================= test session starts ============================== collecting ... collected 4 items / 2 deselected / 2 selected test_main.py::test_calc_pi[1000001] test_main.py::test_calc_pi[1000003] ================= 2 passed, 2 deselected, 2 warnings in 0.91s ================== PASSED [ 50%]PASSED [100%]
まとめ
Pytestでカスタムマークを使ってテストを実行してみました。Pytestでテストケースが増えてきた場合にはカスタムマークをテストケースに付けることで新しく実装した機能だけとか特定のリソースを使ったテストケースのみをテストしたいといった場合にはとても役に立つ機能だと思います。なお、カスタムマークを使わない場合は-k
オプションを使うことでテスト名の部分一致で実行するテストを選択することができます。ただ個人的にはカスタムマークを使った完全一致でのテスト選択のほうが目的のテストをピンポイントで実行できるので使い勝手が良いのではと思います。
最後まで読んで頂いてありがとうございました。